﻿using System;
using System.Runtime.InteropServices;

namespace Vanara.PInvoke
{
	public static partial class User32
	{
		/// <summary>The delegate for a hook procedure set by SetWindowsHookEx.</summary>
		/// <param name="nCode">
		/// A hook code that the hook procedure uses to determine the action to perform. The value of the hook code depends on the type of
		/// the hook; each type has its own characteristic set of hook codes.
		/// </param>
		/// <param name="wParam">
		/// The value depends on the hook code, but typically contains information about a message that was sent or posted.
		/// </param>
		/// <param name="lParam">
		/// The value depends on the hook code, but typically contains information about a message that was sent or posted.
		/// </param>
		/// <returns>The value depends on the hook code.</returns>
		[PInvokeData("WinUser.h")]
		[UnmanagedFunctionPointer(CallingConvention.Winapi)]
		public delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);

		/// <summary>
		/// <para>
		/// An application-defined callback (or hook) function that the system calls in response to events generated by an accessible
		/// object. The hook function processes the event notifications as required. Clients install the hook function and request specific
		/// types of event notifications by calling SetWinEventHook.
		/// </para>
		/// <para>
		/// The WINEVENTPROC type defines a pointer to this callback function. WinEventProc is a placeholder for the application-defined
		/// function name.
		/// </para>
		/// </summary>
		/// <param name="hWinEventHook">
		/// <para>Type: <c>HWINEVENTHOOK</c></para>
		/// <para>
		/// Handle to an event hook function. This value is returned by SetWinEventHook when the hook function is installed and is specific
		/// to each instance of the hook function.
		/// </para>
		/// </param>
		/// <param name="winEvent">
		/// <para>Type: <c>DWORD</c></para>
		/// <para>Specifies the event that occurred. This value is one of the event constants.</para>
		/// </param>
		/// <param name="hwnd">
		/// <para>Type: <c>HWND</c></para>
		/// <para>
		/// Handle to the window that generates the event, or <c>NULL</c> if no window is associated with the event. For example, the mouse
		/// pointer is not associated with a window.
		/// </para>
		/// </param>
		/// <param name="idObject">
		/// <para>Type: <c>LONG</c></para>
		/// <para>Identifies the object associated with the event. This is one of the object identifiers or a custom object ID.</para>
		/// </param>
		/// <param name="idChild">
		/// <para>Type: <c>LONG</c></para>
		/// <para>
		/// Identifies whether the event was triggered by an object or a child element of the object. If this value is CHILDID_SELF, the
		/// event was triggered by the object; otherwise, this value is the child ID of the element that triggered the event.
		/// </para>
		/// </param>
		/// <param name="idEventThread">The identifier event thread.</param>
		/// <param name="dwmsEventTime">
		/// <para>Type: <c>DWORD</c></para>
		/// <para>Specifies the time, in milliseconds, that the event was generated.</para>
		/// </param>
		/// <remarks>
		/// <para>Within the hook function, the parameters hwnd, idObject, and idChild are used when calling AccessibleObjectFromEvent.</para>
		/// <para>Servers generate events by calling NotifyWinEvent.</para>
		/// <para>Create multiple callback functions to handle different events. For more information, see Registering a Hook Function.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nc-winuser-wineventproc WINEVENTPROC Wineventproc; void
		// Wineventproc( HWINEVENTHOOK hWinEventHook, DWORD event, HWND hwnd, LONG idObject, LONG idChild, DWORD idEventThread, DWORD
		// dwmsEventTime ) {...}
		[PInvokeData("winuser.h", MSDNShortId = "5fe3cacc-4563-43da-960d-729d3fe4ff70")]
		[UnmanagedFunctionPointer(CallingConvention.Winapi)]
		public delegate void WinEventProc(HWINEVENTHOOK hWinEventHook, uint winEvent, HWND hwnd, int idObject, int idChild, uint idEventThread, uint dwmsEventTime);

		/// <summary>The type of hook procedure to be installed.</summary>
		[PInvokeData("WinUser.h", MSDNShortId = "ms644990")]
		public enum HookType
		{
			/// <summary>
			/// Installs a hook procedure that monitors messages generated as a result of an input event in a dialog box, message box, menu,
			/// or scroll bar. For more information, see the MessageProc hook procedure.
			/// </summary>
			WH_MSGFILTER = -1,

			/// <summary>
			/// Installs a hook procedure that records input messages posted to the system message queue. This hook is useful for recording
			/// macros. For more information, see the JournalRecordProc hook procedure.
			/// </summary>
			WH_JOURNALRECORD = 0,

			/// <summary>
			/// Installs a hook procedure that posts messages previously recorded by a WH_JOURNALRECORD hook procedure. For more
			/// information, see the JournalPlaybackProc hook procedure.
			/// </summary>
			WH_JOURNALPLAYBACK = 1,

			/// <summary>
			/// Installs a hook procedure that monitors keystroke messages. For more information, see the KeyboardProc hook procedure.
			/// </summary>
			WH_KEYBOARD = 2,

			/// <summary>
			/// Installs a hook procedure that monitors messages posted to a message queue. For more information, see the GetMsgProc hook procedure.
			/// </summary>
			WH_GETMESSAGE = 3,

			/// <summary>
			/// Installs a hook procedure that monitors messages before the system sends them to the destination window procedure. For more
			/// information, see the CallWndProc hook procedure.
			/// </summary>
			WH_CALLWNDPROC = 4,

			/// <summary>
			/// Installs a hook procedure that receives notifications useful to a CBT application. For more information, see the CBTProc
			/// hook procedure.
			/// </summary>
			WH_CBT = 5,

			/// <summary>
			/// Installs a hook procedure that monitors messages generated as a result of an input event in a dialog box, message box, menu,
			/// or scroll bar. The hook procedure monitors these messages for all applications in the same desktop as the calling thread.
			/// For more information, see the SysMsgProc hook procedure.
			/// </summary>
			WH_SYSMSGFILTER = 6,

			/// <summary>Installs a hook procedure that monitors mouse messages. For more information, see the MouseProc hook procedure.</summary>
			WH_MOUSE = 7,

			/// <summary></summary>
			WH_HARDWARE = 8,

			/// <summary>
			/// Installs a hook procedure useful for debugging other hook procedures. For more information, see the DebugProc hook procedure.
			/// </summary>
			WH_DEBUG = 9,

			/// <summary>
			/// Installs a hook procedure that receives notifications useful to shell applications. For more information, see the ShellProc
			/// hook procedure.
			/// </summary>
			WH_SHELL = 10,

			/// <summary>
			/// Installs a hook procedure that will be called when the application's foreground thread is about to become idle. This hook is
			/// useful for performing low priority tasks during idle time. For more information, see the ForegroundIdleProc hook procedure.
			/// </summary>
			WH_FOREGROUNDIDLE = 11,

			/// <summary>
			/// Installs a hook procedure that monitors messages after they have been processed by the destination window procedure. For
			/// more information, see the CallWndRetProc hook procedure.
			/// </summary>
			WH_CALLWNDPROCRET = 12,

			/// <summary>
			/// Installs a hook procedure that monitors low-level keyboard input events. For more information, see the LowLevelKeyboardProc
			/// hook procedure.
			/// </summary>
			WH_KEYBOARD_LL = 13,

			/// <summary>
			/// Installs a hook procedure that monitors low-level mouse input events. For more information, see the LowLevelMouseProc hook procedure.
			/// </summary>
			WH_MOUSE_LL = 14
		}

		/// <summary>Flags for <see cref="SetWinEventHook"/>.</summary>
		[PInvokeData("winuser.h", MSDNShortId = "090bda1b-0635-4aa3-ae33-3987b36e30b8")]
		[Flags]
		public enum WINEVENT
		{
			/// <summary>
			/// The DLL that contains the callback function is mapped into the address space of the process that generates the event. With
			/// this flag, the system sends event notifications to the callback function as they occur. The hook function must be in a DLL
			/// when this flag is specified. This flag has no effect when both the calling process and the generating process are not 32-bit
			/// or 64-bit processes, or when the generating process is a console application. For more information, see In-Context Hook Functions.
			/// </summary>
			WINEVENT_INCONTEXT = 0,

			/// <summary>
			/// The callback function is not mapped into the address space of the process that generates the event. Because the hook
			/// function is called across process boundaries, the system must queue events. Although this method is asynchronous, events are
			/// guaranteed to be in sequential order. For more information, see Out-of-Context Hook Functions.
			/// </summary>
			WINEVENT_OUTOFCONTEXT = 1,

			/// <summary>
			/// Prevents this instance of the hook from receiving the events that are generated by threads in this process. This flag does
			/// not prevent threads from generating events.
			/// </summary>
			WINEVENT_SKIPOWNPROCESS = 2,

			/// <summary>
			/// Prevents this instance of the hook from receiving the events that are generated by the thread that is registering this hook.
			/// </summary>
			WINEVENT_SKIPOWNTHREAD = 4,
		}

		/// <summary>
		/// <para>
		/// Passes the specified message and hook code to the hook procedures associated with the WH_SYSMSGFILTER and WH_MSGFILTER hooks. A
		/// <c>WH_SYSMSGFILTER</c> or <c>WH_MSGFILTER</c> hook procedure is an application-defined callback function that examines and,
		/// optionally, modifies messages for a dialog box, message box, menu, or scroll bar.
		/// </para>
		/// </summary>
		/// <param name="lpMsg">
		/// <para>Type: <c>LPMSG</c></para>
		/// <para>A pointer to an MSG structure that contains the message to be passed to the hook procedures.</para>
		/// </param>
		/// <param name="nCode">
		/// <para>Type: <c>int</c></para>
		/// <para>
		/// An application-defined code used by the hook procedure to determine how to process the message. The code must not have the same
		/// value as system-defined hook codes (MSGF_ and HC_) associated with the WH_SYSMSGFILTER and <c>WH_MSGFILTER</c> hooks.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>Type: <c>Type: <c>BOOL</c></c></para>
		/// <para>If the application should process the message further, the return value is zero.</para>
		/// <para>If the application should not process the message further, the return value is nonzero.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The system calls <c>CallMsgFilter</c> to enable applications to examine and control the flow of messages during internal
		/// processing of dialog boxes, message boxes, menus, and scroll bars, or when the user activates a different window by pressing the
		/// ALT+TAB key combination.
		/// </para>
		/// <para>Install this hook procedure by using the SetWindowsHookEx function.</para>
		/// <para>Examples</para>
		/// <para>For an example, see WH_MSGFILTER and WH_SYSMSGFILTER Hooks.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-callmsgfiltera BOOL CallMsgFilterA( LPMSG lpMsg, int
		// nCode );
		[DllImport(Lib.User32, SetLastError = false, CharSet = CharSet.Auto)]
		[PInvokeData("winuser.h", MSDNShortId = "callmsgfilter")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CallMsgFilter(ref MSG lpMsg, int nCode);

		/// <summary>
		/// <para>
		/// Passes the hook information to the next hook procedure in the current hook chain. A hook procedure can call this function either
		/// before or after processing the hook information.
		/// </para>
		/// </summary>
		/// <param name="hhk">
		/// <para>Type: <c>HHOOK</c></para>
		/// <para>This parameter is ignored.</para>
		/// </param>
		/// <param name="nCode">
		/// <para>Type: <c>int</c></para>
		/// <para>
		/// The hook code passed to the current hook procedure. The next hook procedure uses this code to determine how to process the hook information.
		/// </para>
		/// </param>
		/// <param name="wParam">
		/// <para>Type: <c>WPARAM</c></para>
		/// <para>
		/// The wParam value passed to the current hook procedure. The meaning of this parameter depends on the type of hook associated with
		/// the current hook chain.
		/// </para>
		/// </param>
		/// <param name="lParam">
		/// <para>Type: <c>LPARAM</c></para>
		/// <para>
		/// The lParam value passed to the current hook procedure. The meaning of this parameter depends on the type of hook associated with
		/// the current hook chain.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>Type: <c>Type: <c>LRESULT</c></c></para>
		/// <para>
		/// This value is returned by the next hook procedure in the chain. The current hook procedure must also return this value. The
		/// meaning of the return value depends on the hook type. For more information, see the descriptions of the individual hook procedures.
		/// </para>
		/// </returns>
		/// <remarks>
		/// <para>Hook procedures are installed in chains for particular hook types. <c>CallNextHookEx</c> calls the next hook in the chain.</para>
		/// <para>
		/// Calling <c>CallNextHookEx</c> is optional, but it is highly recommended; otherwise, other applications that have installed hooks
		/// will not receive hook notifications and may behave incorrectly as a result. You should call <c>CallNextHookEx</c> unless you
		/// absolutely need to prevent the notification from being seen by other applications.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-callnexthookex LRESULT CallNextHookEx( HHOOK hhk, int
		// nCode, WPARAM wParam, LPARAM lParam );
		[DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("winuser.h", MSDNShortId = "callnexthookex")]
		public static extern IntPtr CallNextHookEx(HHOOK hhk, int nCode, IntPtr wParam, IntPtr lParam);

		/// <summary>Determines whether there is an installed WinEvent hook that might be notified of a specified event.</summary>
		/// <param name="winEvent">
		/// <para>Type: <c>DWORD</c></para>
		/// <para>
		/// The event constant that hooks might be notified of. The function checks whether there is an installed hook for this event constant.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>Type: <c>BOOL</c></para>
		/// <para>If there is a hook to be notified of the specified event, the return value is <c>TRUE</c>.</para>
		/// <para>If there are no hooks to be notified of the specified event, the return value is <c>FALSE</c>.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// This method is guaranteed to never return a false negative. If this method returns <c>FALSE</c>, it means that no hooks in the
		/// system would be notified of the event. However, this method may return a false positive. In other words, it may return
		/// <c>TRUE</c> even though there are no hooks that would be notified. Thus, it is safe for components to circumvent some work if
		/// this method returns <c>FALSE</c>.
		/// </para>
		/// <para>Event hooks can be installed at any time, so server developers should not cache the return value for long periods of time.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-iswineventhookinstalled BOOL IsWinEventHookInstalled(
		// DWORD event );
		[DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("winuser.h", MSDNShortId = "bc1e97ad-748d-420a-8c9a-72a555b685e1")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool IsWinEventHookInstalled(uint winEvent);

		/// <summary>
		/// <para>
		/// Installs an application-defined hook procedure into a hook chain. You would install a hook procedure to monitor the system for
		/// certain types of events. These events are associated either with a specific thread or with all threads in the same desktop as
		/// the calling thread.
		/// </para>
		/// </summary>
		/// <param name="idHook">
		/// <para>Type: <c>int</c></para>
		/// <para>The type of hook procedure to be installed. This parameter can be one of the following values.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>WH_CALLWNDPROC 4</term>
		/// <term>
		/// Installs a hook procedure that monitors messages before the system sends them to the destination window procedure. For more
		/// information, see the CallWndProc hook procedure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WH_CALLWNDPROCRET 12</term>
		/// <term>
		/// Installs a hook procedure that monitors messages after they have been processed by the destination window procedure. For more
		/// information, see the CallWndRetProc hook procedure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WH_CBT 5</term>
		/// <term>
		/// Installs a hook procedure that receives notifications useful to a CBT application. For more information, see the CBTProc hook procedure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WH_DEBUG 9</term>
		/// <term>Installs a hook procedure useful for debugging other hook procedures. For more information, see the DebugProc hook procedure.</term>
		/// </item>
		/// <item>
		/// <term>WH_FOREGROUNDIDLE 11</term>
		/// <term>
		/// Installs a hook procedure that will be called when the application's foreground thread is about to become idle. This hook is
		/// useful for performing low priority tasks during idle time. For more information, see the ForegroundIdleProc hook procedure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WH_GETMESSAGE 3</term>
		/// <term>
		/// Installs a hook procedure that monitors messages posted to a message queue. For more information, see the GetMsgProc hook procedure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WH_JOURNALPLAYBACK 1</term>
		/// <term>
		/// Installs a hook procedure that posts messages previously recorded by a WH_JOURNALRECORD hook procedure. For more information,
		/// see the JournalPlaybackProc hook procedure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WH_JOURNALRECORD 0</term>
		/// <term>
		/// Installs a hook procedure that records input messages posted to the system message queue. This hook is useful for recording
		/// macros. For more information, see the JournalRecordProc hook procedure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WH_KEYBOARD 2</term>
		/// <term>Installs a hook procedure that monitors keystroke messages. For more information, see the KeyboardProc hook procedure.</term>
		/// </item>
		/// <item>
		/// <term>WH_KEYBOARD_LL 13</term>
		/// <term>
		/// Installs a hook procedure that monitors low-level keyboard input events. For more information, see the LowLevelKeyboardProc hook procedure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WH_MOUSE 7</term>
		/// <term>Installs a hook procedure that monitors mouse messages. For more information, see the MouseProc hook procedure.</term>
		/// </item>
		/// <item>
		/// <term>WH_MOUSE_LL 14</term>
		/// <term>
		/// Installs a hook procedure that monitors low-level mouse input events. For more information, see the LowLevelMouseProc hook procedure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WH_MSGFILTER -1</term>
		/// <term>
		/// Installs a hook procedure that monitors messages generated as a result of an input event in a dialog box, message box, menu, or
		/// scroll bar. For more information, see the MessageProc hook procedure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WH_SHELL 10</term>
		/// <term>
		/// Installs a hook procedure that receives notifications useful to shell applications. For more information, see the ShellProc hook procedure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WH_SYSMSGFILTER 6</term>
		/// <term>
		/// Installs a hook procedure that monitors messages generated as a result of an input event in a dialog box, message box, menu, or
		/// scroll bar. The hook procedure monitors these messages for all applications in the same desktop as the calling thread. For more
		/// information, see the SysMsgProc hook procedure.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="lpfn">
		/// <para>Type: <c>HOOKPROC</c></para>
		/// <para>
		/// A pointer to the hook procedure. If the dwThreadId parameter is zero or specifies the identifier of a thread created by a
		/// different process, the lpfn parameter must point to a hook procedure in a DLL. Otherwise, lpfn can point to a hook procedure in
		/// the code associated with the current process.
		/// </para>
		/// </param>
		/// <param name="hmod">
		/// <para>Type: <c>HINSTANCE</c></para>
		/// <para>
		/// A handle to the DLL containing the hook procedure pointed to by the lpfn parameter. The hMod parameter must be set to
		/// <c>NULL</c> if the dwThreadId parameter specifies a thread created by the current process and if the hook procedure is within
		/// the code associated with the current process.
		/// </para>
		/// </param>
		/// <param name="dwThreadId">
		/// <para>Type: <c>DWORD</c></para>
		/// <para>
		/// The identifier of the thread with which the hook procedure is to be associated. For desktop apps, if this parameter is zero, the
		/// hook procedure is associated with all existing threads running in the same desktop as the calling thread. For Windows Store
		/// apps, see the Remarks section.
		/// </para>
		/// </param>
		/// <returns>
		/// <para>Type: <c>Type: <c>HHOOK</c></c></para>
		/// <para>If the function succeeds, the return value is the handle to the hook procedure.</para>
		/// <para>If the function fails, the return value is <c>NULL</c>. To get extended error information, call GetLastError.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// <c>SetWindowsHookEx</c> can be used to inject a DLL into another process. A 32-bit DLL cannot be injected into a 64-bit process,
		/// and a 64-bit DLL cannot be injected into a 32-bit process. If an application requires the use of hooks in other processes, it is
		/// required that a 32-bit application call <c>SetWindowsHookEx</c> to inject a 32-bit DLL into 32-bit processes, and a 64-bit
		/// application call <c>SetWindowsHookEx</c> to inject a 64-bit DLL into 64-bit processes. The 32-bit and 64-bit DLLs must have
		/// different names.
		/// </para>
		/// <para>
		/// Because hooks run in the context of an application, they must match the "bitness" of the application. If a 32-bit application
		/// installs a global hook on 64-bit Windows, the 32-bit hook is injected into each 32-bit process (the usual security boundaries
		/// apply). In a 64-bit process, the threads are still marked as "hooked." However, because a 32-bit application must run the hook
		/// code, the system executes the hook in the hooking app's context; specifically, on the thread that called
		/// <c>SetWindowsHookEx</c>. This means that the hooking application must continue to pump messages or it might block the normal
		/// functioning of the 64-bit processes.
		/// </para>
		/// <para>
		/// If a 64-bit application installs a global hook on 64-bit Windows, the 64-bit hook is injected into each 64-bit process, while
		/// all 32-bit processes use a callback to the hooking application.
		/// </para>
		/// <para>
		/// To hook all applications on the desktop of a 64-bit Windows installation, install a 32-bit global hook and a 64-bit global hook,
		/// each from appropriate processes, and be sure to keep pumping messages in the hooking application to avoid blocking normal
		/// functioning. If you already have a 32-bit global hooking application and it doesn't need to run in each application's context,
		/// you may not need to create a 64-bit version.
		/// </para>
		/// <para>
		/// An error may occur if the hMod parameter is <c>NULL</c> and the dwThreadId parameter is zero or specifies the identifier of a
		/// thread created by another process.
		/// </para>
		/// <para>
		/// Calling the CallNextHookEx function to chain to the next hook procedure is optional, but it is highly recommended; otherwise,
		/// other applications that have installed hooks will not receive hook notifications and may behave incorrectly as a result. You
		/// should call <c>CallNextHookEx</c> unless you absolutely need to prevent the notification from being seen by other applications.
		/// </para>
		/// <para>
		/// Before terminating, an application must call the UnhookWindowsHookEx function to free system resources associated with the hook.
		/// </para>
		/// <para>
		/// The scope of a hook depends on the hook type. Some hooks can be set only with global scope; others can also be set for only a
		/// specific thread, as shown in the following table.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Hook</term>
		/// <term>Scope</term>
		/// </listheader>
		/// <item>
		/// <term>WH_CALLWNDPROC</term>
		/// <term>Thread or global</term>
		/// </item>
		/// <item>
		/// <term>WH_CALLWNDPROCRET</term>
		/// <term>Thread or global</term>
		/// </item>
		/// <item>
		/// <term>WH_CBT</term>
		/// <term>Thread or global</term>
		/// </item>
		/// <item>
		/// <term>WH_DEBUG</term>
		/// <term>Thread or global</term>
		/// </item>
		/// <item>
		/// <term>WH_FOREGROUNDIDLE</term>
		/// <term>Thread or global</term>
		/// </item>
		/// <item>
		/// <term>WH_GETMESSAGE</term>
		/// <term>Thread or global</term>
		/// </item>
		/// <item>
		/// <term>WH_JOURNALPLAYBACK</term>
		/// <term>Global only</term>
		/// </item>
		/// <item>
		/// <term>WH_JOURNALRECORD</term>
		/// <term>Global only</term>
		/// </item>
		/// <item>
		/// <term>WH_KEYBOARD</term>
		/// <term>Thread or global</term>
		/// </item>
		/// <item>
		/// <term>WH_KEYBOARD_LL</term>
		/// <term>Global only</term>
		/// </item>
		/// <item>
		/// <term>WH_MOUSE</term>
		/// <term>Thread or global</term>
		/// </item>
		/// <item>
		/// <term>WH_MOUSE_LL</term>
		/// <term>Global only</term>
		/// </item>
		/// <item>
		/// <term>WH_MSGFILTER</term>
		/// <term>Thread or global</term>
		/// </item>
		/// <item>
		/// <term>WH_SHELL</term>
		/// <term>Thread or global</term>
		/// </item>
		/// <item>
		/// <term>WH_SYSMSGFILTER</term>
		/// <term>Global only</term>
		/// </item>
		/// </list>
		/// <para>
		/// For a specified hook type, thread hooks are called first, then global hooks. Be aware that the WH_MOUSE, WH_KEYBOARD,
		/// WH_JOURNAL*, WH_SHELL, and low-level hooks can be called on the thread that installed the hook rather than the thread processing
		/// the hook. For these hooks, it is possible that both the 32-bit and 64-bit hooks will be called if a 32-bit hook is ahead of a
		/// 64-bit hook in the hook chain.
		/// </para>
		/// <para>
		/// The global hooks are a shared resource, and installing one affects all applications in the same desktop as the calling thread.
		/// All global hook functions must be in libraries. Global hooks should be restricted to special-purpose applications or to use as a
		/// development aid during application debugging. Libraries that no longer need a hook should remove its hook procedure.
		/// </para>
		/// <para>
		/// <c>Windows Store app development</c> If dwThreadId is zero, then window hook DLLs are not loaded in-process for the Windows
		/// Store app processes and the Windows Runtime broker process unless they are installed by either UIAccess processes (accessibility
		/// tools). The notification is delivered on the installer's thread for these hooks:
		/// </para>
		/// <list type="bullet">
		/// <item>
		/// <term>WH_JOURNALPLAYBACK</term>
		/// </item>
		/// <item>
		/// <term>WH_JOURNALRECORD</term>
		/// </item>
		/// <item>
		/// <term>WH_KEYBOARD</term>
		/// </item>
		/// <item>
		/// <term>WH_KEYBOARD_LL</term>
		/// </item>
		/// <item>
		/// <term>WH_MOUSE</term>
		/// </item>
		/// <item>
		/// <term>WH_MOUSE_LL</term>
		/// </item>
		/// </list>
		/// <para>
		/// This behavior is similar to what happens when there is an architecture mismatch between the hook DLL and the target application
		/// process, for example, when the hook DLL is 32-bit and the application process 64-bit.
		/// </para>
		/// <para>Examples</para>
		/// <para>For an example, see Installing and Releasing Hook Procedures.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setwindowshookexa HHOOK SetWindowsHookExA( int idHook,
		// HOOKPROC lpfn, HINSTANCE hmod, DWORD dwThreadId );
		[DllImport(Lib.User32, SetLastError = true, CharSet = CharSet.Auto)]
		[PInvokeData("winuser.h", MSDNShortId = "setwindowshookex")]
		public static extern SafeHHOOK SetWindowsHookEx(HookType idHook, HookProc lpfn, HINSTANCE hmod, int dwThreadId);

		/// <summary>Sets an event hook function for a range of events.</summary>
		/// <param name="eventMin">
		/// <para>Type: <c>UINT</c></para>
		/// <para>
		/// Specifies the event constant for the lowest event value in the range of events that are handled by the hook function. This
		/// parameter can be set to <c>EVENT_MIN</c> to indicate the lowest possible event value. See <see cref="EventConstants"/> for
		/// defined values.
		/// </para>
		/// </param>
		/// <param name="eventMax">
		/// <para>Type: <c>UINT</c></para>
		/// <para>
		/// Specifies the event constant for the highest event value in the range of events that are handled by the hook function. This
		/// parameter can be set to EVENT_MAX to indicate the highest possible event value. See <see cref="EventConstants"/> for defined values.
		/// </para>
		/// </param>
		/// <param name="hmodWinEventProc">
		/// <para>Type: <c>HMODULE</c></para>
		/// <para>
		/// Handle to the DLL that contains the hook function at lpfnWinEventProc, if the WINEVENT_INCONTEXT flag is specified in the
		/// dwFlags parameter. If the hook function is not located in a DLL, or if the WINEVENT_OUTOFCONTEXT flag is specified, this
		/// parameter is <c>NULL</c>.
		/// </para>
		/// </param>
		/// <param name="pfnWinEventProc">
		/// <para>Type: <c>WINEVENTPROC</c></para>
		/// <para>Pointer to the event hook function. For more information about this function, see WinEventProc.</para>
		/// </param>
		/// <param name="idProcess">
		/// <para>Type: <c>DWORD</c></para>
		/// <para>
		/// Specifies the ID of the process from which the hook function receives events. Specify zero (0) to receive events from all
		/// processes on the current desktop.
		/// </para>
		/// </param>
		/// <param name="idThread">
		/// <para>Type: <c>DWORD</c></para>
		/// <para>
		/// Specifies the ID of the thread from which the hook function receives events. If this parameter is zero, the hook function is
		/// associated with all existing threads on the current desktop.
		/// </para>
		/// </param>
		/// <param name="dwFlags">
		/// <para>Type: <c>UINT</c></para>
		/// <para>Flag values that specify the location of the hook function and of the events to be skipped. The following flags are valid:</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>WINEVENT_INCONTEXT</term>
		/// <term>
		/// The DLL that contains the callback function is mapped into the address space of the process that generates the event. With this
		/// flag, the system sends event notifications to the callback function as they occur. The hook function must be in a DLL when this
		/// flag is specified. This flag has no effect when both the calling process and the generating process are not 32-bit or 64-bit
		/// processes, or when the generating process is a console application. For more information, see In-Context Hook Functions.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WINEVENT_OUTOFCONTEXT</term>
		/// <term>
		/// The callback function is not mapped into the address space of the process that generates the event. Because the hook function is
		/// called across process boundaries, the system must queue events. Although this method is asynchronous, events are guaranteed to
		/// be in sequential order. For more information, see Out-of-Context Hook Functions.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WINEVENT_SKIPOWNPROCESS</term>
		/// <term>
		/// Prevents this instance of the hook from receiving the events that are generated by threads in this process. This flag does not
		/// prevent threads from generating events.
		/// </term>
		/// </item>
		/// <item>
		/// <term>WINEVENT_SKIPOWNTHREAD</term>
		/// <term>
		/// Prevents this instance of the hook from receiving the events that are generated by the thread that is registering this hook.
		/// </term>
		/// </item>
		/// </list>
		/// <para>The following flag combinations are valid:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>WINEVENT_INCONTEXT | WINEVENT_SKIPOWNPROCESS</term>
		/// </item>
		/// <item>
		/// <term>WINEVENT_INCONTEXT | WINEVENT_SKIPOWNTHREAD</term>
		/// </item>
		/// <item>
		/// <term>WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS</term>
		/// </item>
		/// <item>
		/// <term>WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNTHREAD</term>
		/// </item>
		/// </list>
		/// <para>Additionally, client applications can specify WINEVENT_INCONTEXT, or WINEVENT_OUTOFCONTEXT alone.</para>
		/// <para>See Remarks section for information on Windows Store app development.</para>
		/// </param>
		/// <returns>
		/// <para>Type: <c>HWINEVENTHOOK</c></para>
		/// <para>
		/// If successful, returns an HWINEVENTHOOK value that identifies this event hook instance. Applications save this return value to
		/// use it with the UnhookWinEvent function.
		/// </para>
		/// <para>If unsuccessful, returns zero.</para>
		/// </returns>
		/// <remarks>
		/// <para>This function allows clients to specify which processes and threads they are interested in.</para>
		/// <para>
		/// If the idProcess parameter is nonzero and idThread is zero, the hook function receives the specified events from all threads in
		/// that process. If the idProcess parameter is zero and idThread is nonzero, the hook function receives the specified events only
		/// from the thread specified by idThread. If both are zero, the hook function receives the specified events from all threads and processes.
		/// </para>
		/// <para>
		/// Clients can call <c>SetWinEventHook</c> multiple times if they want to register additional hook functions or listen for
		/// additional events.
		/// </para>
		/// <para>The client thread that calls <c>SetWinEventHook</c> must have a message loop in order to receive events.</para>
		/// <para>
		/// When you use <c>SetWinEventHook</c> to set a callback in managed code, you should use the GCHandle structure to avoid
		/// exceptions. This tells the garbage collector not to move the callback.
		/// </para>
		/// <para>
		/// For out-of-context events, the event is delivered on the same thread that called <c>SetWinEventHook</c>. In some situations,
		/// even if you request WINEVENT_INCONTEXT events, the events will still be delivered out-of-context. These scenarios include events
		/// from console windows and events from processes that have a different bit-depth (64 bit versus 32 bits) than the caller.
		/// </para>
		/// <para>
		/// While a hook function processes an event, additional events may be triggered, which may cause the hook function to reenter
		/// before the processing for the original event is finished. The problem with reentrancy in hook functions is that events are
		/// completed out of sequence unless the hook function handles this situation. For more information, see Guarding Against Reentrancy.
		/// </para>
		/// <para>
		/// <c>Windows Store app development</c> If dwFlags is WINEVENT_INCONTEXT AND (idProcess = 0 | idThread = 0), then window hook DLLs
		/// are not loaded in-process for the Windows Store app processes and the Windows Runtime broker process unless they are installed
		/// by UIAccess processes (accessibility tools). The notification is delivered on the installer's thread.
		/// </para>
		/// <para>
		/// This behavior is similar to what happens when there is an architecture mismatch between the hook DLL and the target application
		/// process, for example, when the hook DLL is 32-bit and the application process 64-bit.
		/// </para>
		/// <para>Examples</para>
		/// <para>
		/// The following example code shows how a client application might listen for menu-start and menu-end events. For simplicity, the
		/// event handler just sends some information to the standard output.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setwineventhook HWINEVENTHOOK SetWinEventHook( DWORD
		// eventMin, DWORD eventMax, HMODULE hmodWinEventProc, WINEVENTPROC pfnWinEventProc, DWORD idProcess, DWORD idThread, DWORD dwFlags );
		[DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("winuser.h", MSDNShortId = "090bda1b-0635-4aa3-ae33-3987b36e30b8")]
		public static extern HWINEVENTHOOK SetWinEventHook(uint eventMin, uint eventMax, HINSTANCE hmodWinEventProc, WinEventProc pfnWinEventProc, uint idProcess, uint idThread, WINEVENT dwFlags);

		/// <summary>
		/// <para>Removes a hook procedure installed in a hook chain by the SetWindowsHookEx function.</para>
		/// </summary>
		/// <param name="hhk">
		/// <para>Type: <c>HHOOK</c></para>
		/// <para>A handle to the hook to be removed. This parameter is a hook handle obtained by a previous call to SetWindowsHookEx.</para>
		/// </param>
		/// <returns>
		/// <para>Type: <c>Type: <c>BOOL</c></c></para>
		/// <para>If the function succeeds, the return value is nonzero.</para>
		/// <para>If the function fails, the return value is zero. To get extended error information, call GetLastError.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// The hook procedure can be in the state of being called by another thread even after <c>UnhookWindowsHookEx</c> returns. If the
		/// hook procedure is not being called concurrently, the hook procedure is removed immediately before <c>UnhookWindowsHookEx</c> returns.
		/// </para>
		/// <para>Examples</para>
		/// <para>For an example, see Monitoring System Events.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-unhookwindowshookex BOOL UnhookWindowsHookEx( HHOOK hhk );
		[DllImport(Lib.User32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("winuser.h", MSDNShortId = "unhookwindowshookex")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool UnhookWindowsHookEx(HHOOK hhk);

		/// <summary>Removes an event hook function created by a previous call to SetWinEventHook.</summary>
		/// <param name="hWinEventHook">
		/// <para>Type: <c>HWINEVENTHOOK</c></para>
		/// <para>Handle to the event hook returned in the previous call to SetWinEventHook.</para>
		/// </param>
		/// <returns>
		/// <para>Type: <c>BOOL</c></para>
		/// <para>If successful, returns <c>TRUE</c>; otherwise, returns <c>FALSE</c>.</para>
		/// <para>Three common errors cause this function to fail:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>The hWinEventHook parameter is <c>NULL</c> or not valid.</term>
		/// </item>
		/// <item>
		/// <term>The event hook specified by hWinEventHook was already removed.</term>
		/// </item>
		/// <item>
		/// <term><c>UnhookWinEvent</c> is called from a thread that is different from the original call to SetWinEventHook.</term>
		/// </item>
		/// </list>
		/// </returns>
		/// <remarks>
		/// <para>
		/// This function removes the event hook specified by hWinEventHook that prevents the corresponding callback function from receiving
		/// further event notifications. If the client's thread ends, the system automatically calls this function.
		/// </para>
		/// <para>
		/// Call this function from the same thread that installed the event hook. <c>UnhookWinEvent</c> fails if called from a thread
		/// different from the call that corresponds to SetWinEventHook.
		/// </para>
		/// <para>
		/// If WINEVENT_INCONTEXT was specified when this event hook was installed, the system attempts to unload the corresponding DLL from
		/// all processes that loaded it. Although unloading does not occur immediately, the hook function is not called after
		/// <c>UnhookWinEvent</c> returns. For more information on WINEVENT_INCONTEXT, see In-Context Hook Functions.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-unhookwinevent BOOL UnhookWinEvent( HWINEVENTHOOK
		// hWinEventHook );
		[DllImport(Lib.User32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("winuser.h", MSDNShortId = "5cffb279-85e1-4f7a-8bbb-d0d618f6afcd")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool UnhookWinEvent(HWINEVENTHOOK hWinEventHook);

		/// <summary>
		/// <para>Contains information passed to a <c>WH_CBT</c> hook procedure, CBTProc, before a window is created.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-tagcbt_createwnda typedef struct tagCBT_CREATEWNDA {
		// struct tagCREATESTRUCTA *lpcs; HWND hwndInsertAfter; } CBT_CREATEWNDA, *LPCBT_CREATEWNDA;
		[PInvokeData("winuser.h", MSDNShortId = "cbt_createwnd.htm")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct CBT_CREATEWND
		{
			/// <summary>
			/// <para>Type: <c>LPCREATESTRUCT</c></para>
			/// <para>A pointer to a CREATESTRUCT structure that contains initialization parameters for the window about to be created.</para>
			/// </summary>
			public IntPtr lpcs;

			/// <summary>
			/// <para>Type: <c>HWND</c></para>
			/// <para>
			/// A handle to the window whose position in the Z order precedes that of the window being created. This member can also be <c>NULL</c>.
			/// </para>
			/// </summary>
			public HWND hwndInsertAfter;
		}

		/// <summary>
		/// <para>Contains information passed to a <c>WH_CBT</c> hook procedure, CBTProc, before a window is activated.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-tagcbtactivatestruct typedef struct tagCBTACTIVATESTRUCT
		// { BOOL fMouse; HWND hWndActive; } CBTACTIVATESTRUCT, *LPCBTACTIVATESTRUCT;
		[PInvokeData("winuser.h", MSDNShortId = "cbtactivatestruct.htm")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct CBTACTIVATESTRUCT
		{
			/// <summary>
			/// <para>Type: <c>BOOL</c></para>
			/// <para>This member is <c>TRUE</c> if a mouse click is causing the activation or <c>FALSE</c> if it is not.</para>
			/// </summary>
			[MarshalAs(UnmanagedType.Bool)]
			public bool fMouse;

			/// <summary>
			/// <para>Type: <c>HWND</c></para>
			/// <para>A handle to the active window.</para>
			/// </summary>
			public HWND hWndActive;
		}

		/// <summary>
		/// <para>Defines the message parameters passed to a <c>WH_CALLWNDPROCRET</c> hook procedure, CallWndRetProc.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-tagcwpretstruct typedef struct tagCWPRETSTRUCT { LRESULT
		// lResult; LPARAM lParam; WPARAM wParam; UINT message; HWND hwnd; } CWPRETSTRUCT, *PCWPRETSTRUCT, *NPCWPRETSTRUCT, *LPCWPRETSTRUCT;
		[PInvokeData("winuser.h", MSDNShortId = "cwpretstruct.htm")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct CWPRETSTRUCT
		{
			/// <summary>
			/// <para>Type: <c>LRESULT</c></para>
			/// <para>The return value of the window procedure that processed the message specified by the <c>message</c> value.</para>
			/// </summary>
			public IntPtr lResult;

			/// <summary>
			/// <para>Type: <c>LPARAM</c></para>
			/// <para>Additional information about the message. The exact meaning depends on the <c>message</c> value.</para>
			/// </summary>
			public IntPtr lParam;

			/// <summary>
			/// <para>Type: <c>WPARAM</c></para>
			/// <para>Additional information about the message. The exact meaning depends on the <c>message</c> value.</para>
			/// </summary>
			public IntPtr wParam;

			/// <summary>
			/// <para>Type: <c>UINT</c></para>
			/// <para>The message.</para>
			/// </summary>
			public uint message;

			/// <summary>
			/// <para>Type: <c>HWND</c></para>
			/// <para>A handle to the window that processed the message specified by the <c>message</c> value.</para>
			/// </summary>
			public HWND hwnd;
		}

		/// <summary>
		/// <para>Defines the message parameters passed to a <c>WH_CALLWNDPROC</c> hook procedure, CallWndProc.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-tagcwpstruct typedef struct tagCWPSTRUCT { LPARAM lParam;
		// WPARAM wParam; UINT message; HWND hwnd; } CWPSTRUCT, *PCWPSTRUCT, *NPCWPSTRUCT, *LPCWPSTRUCT;
		[PInvokeData("winuser.h", MSDNShortId = "cwpstruct.htm")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct CWPSTRUCT
		{
			/// <summary>
			/// <para>Type: <c>LPARAM</c></para>
			/// <para>Additional information about the message. The exact meaning depends on the <c>message</c> value.</para>
			/// </summary>
			public IntPtr lParam;

			/// <summary>
			/// <para>Type: <c>WPARAM</c></para>
			/// <para>Additional information about the message. The exact meaning depends on the <c>message</c> value.</para>
			/// </summary>
			public IntPtr wParam;

			/// <summary>
			/// <para>Type: <c>UINT</c></para>
			/// <para>The message.</para>
			/// </summary>
			public uint message;

			/// <summary>
			/// <para>Type: <c>HWND</c></para>
			/// <para>A handle to the window to receive the message.</para>
			/// </summary>
			public HWND hwnd;
		}

		/// <summary>
		/// <para>Contains debugging information passed to a <c>WH_DEBUG</c> hook procedure, DebugProc.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-tagdebughookinfo typedef struct tagDEBUGHOOKINFO { DWORD
		// idThread; DWORD idThreadInstaller; LPARAM lParam; WPARAM wParam; int code; } DEBUGHOOKINFO, *PDEBUGHOOKINFO, *NPDEBUGHOOKINFO, *LPDEBUGHOOKINFO;
		[PInvokeData("winuser.h", MSDNShortId = "debughookinfo.htm")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct DEBUGHOOKINFO
		{
			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>A handle to the thread containing the filter function.</para>
			/// </summary>
			public uint idThread;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>A handle to the thread that installed the debugging filter function.</para>
			/// </summary>
			public uint idThreadInstaller;

			/// <summary>
			/// <para>Type: <c>LPARAM</c></para>
			/// <para>The value to be passed to the hook in the lParam parameter of the DebugProc callback function.</para>
			/// </summary>
			public IntPtr lParam;

			/// <summary>
			/// <para>Type: <c>WPARAM</c></para>
			/// <para>The value to be passed to the hook in the wParam parameter of the DebugProc callback function.</para>
			/// </summary>
			public IntPtr wParam;

			/// <summary>
			/// <para>Type: <c>int</c></para>
			/// <para>The value to be passed to the hook in the nCode parameter of the DebugProc callback function.</para>
			/// </summary>
			public int code;
		}

		/// <summary>
		/// <para>
		/// Contains information about a hardware message sent to the system message queue. This structure is used to store message
		/// information for the JournalPlaybackProc callback function.
		/// </para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-tageventmsg typedef struct tagEVENTMSG { UINT message;
		// UINT paramL; UINT paramH; DWORD time; HWND hwnd; } EVENTMSG, *PEVENTMSGMSG, *NPEVENTMSGMSG, *LPEVENTMSGMSG, *PEVENTMSG,
		// *NPEVENTMSG, *LPEVENTMSG;
		[PInvokeData("winuser.h", MSDNShortId = "eventmsg.htm")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct EVENTMSG
		{
			/// <summary>
			/// <para>Type: <c>UINT</c></para>
			/// <para>The message.</para>
			/// </summary>
			public uint message;

			/// <summary>
			/// <para>Type: <c>UINT</c></para>
			/// <para>Additional information about the message. The exact meaning depends on the <c>message</c> value.</para>
			/// </summary>
			public uint paramL;

			/// <summary>
			/// <para>Type: <c>UINT</c></para>
			/// <para>Additional information about the message. The exact meaning depends on the <c>message</c> value.</para>
			/// </summary>
			public uint paramH;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>The time at which the message was posted.</para>
			/// </summary>
			public uint time;

			/// <summary>
			/// <para>Type: <c>HWND</c></para>
			/// <para>A handle to the window to which the message was posted.</para>
			/// </summary>
			public HWND hwnd;
		}

		/// <summary>Provides a handle to a hook.</summary>
		[StructLayout(LayoutKind.Sequential)]
		public struct HHOOK : IUserHandle
		{
			private IntPtr handle;

			/// <summary>Initializes a new instance of the <see cref="HHOOK"/> struct.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			public HHOOK(IntPtr preexistingHandle) => handle = preexistingHandle;

			/// <summary>Returns an invalid handle by instantiating a <see cref="HHOOK"/> object with <see cref="IntPtr.Zero"/>.</summary>
			public static HHOOK NULL => new HHOOK(IntPtr.Zero);

			/// <summary>Gets a value indicating whether this instance is a null handle.</summary>
			public bool IsNull => handle == IntPtr.Zero;

			/// <summary>Performs an explicit conversion from <see cref="HHOOK"/> to <see cref="IntPtr"/>.</summary>
			/// <param name="h">The handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static explicit operator IntPtr(HHOOK h) => h.handle;

			/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="HHOOK"/>.</summary>
			/// <param name="h">The pointer to a handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator HHOOK(IntPtr h) => new HHOOK(h);

			/// <summary>Implements the operator !=.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator !=(HHOOK h1, HHOOK h2) => !(h1 == h2);

			/// <summary>Implements the operator ==.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator ==(HHOOK h1, HHOOK h2) => h1.Equals(h2);

			/// <inheritdoc/>
			public override bool Equals(object obj) => obj is HHOOK h ? handle == h.handle : false;

			/// <inheritdoc/>
			public override int GetHashCode() => handle.GetHashCode();

			/// <inheritdoc/>
			public IntPtr DangerousGetHandle() => handle;
		}

		/// <summary>Provides a handle to a Windows Event Hook.</summary>
		[StructLayout(LayoutKind.Sequential)]
		public struct HWINEVENTHOOK : IHandle
		{
			private IntPtr handle;

			/// <summary>Initializes a new instance of the <see cref="HWINEVENTHOOK"/> struct.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			public HWINEVENTHOOK(IntPtr preexistingHandle) => handle = preexistingHandle;

			/// <summary>Returns an invalid handle by instantiating a <see cref="HWINEVENTHOOK"/> object with <see cref="IntPtr.Zero"/>.</summary>
			public static HWINEVENTHOOK NULL => new HWINEVENTHOOK(IntPtr.Zero);

			/// <summary>Gets a value indicating whether this instance is a null handle.</summary>
			public bool IsNull => handle == IntPtr.Zero;

			/// <summary>Performs an explicit conversion from <see cref="HWINEVENTHOOK"/> to <see cref="IntPtr"/>.</summary>
			/// <param name="h">The handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static explicit operator IntPtr(HWINEVENTHOOK h) => h.handle;

			/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="HWINEVENTHOOK"/>.</summary>
			/// <param name="h">The pointer to a handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator HWINEVENTHOOK(IntPtr h) => new HWINEVENTHOOK(h);

			/// <summary>Implements the operator !=.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator !=(HWINEVENTHOOK h1, HWINEVENTHOOK h2) => !(h1 == h2);

			/// <summary>Implements the operator ==.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator ==(HWINEVENTHOOK h1, HWINEVENTHOOK h2) => h1.Equals(h2);

			/// <inheritdoc/>
			public override bool Equals(object obj) => obj is HWINEVENTHOOK h ? handle == h.handle : false;

			/// <inheritdoc/>
			public override int GetHashCode() => handle.GetHashCode();

			/// <inheritdoc/>
			public IntPtr DangerousGetHandle() => handle;
		}

		/// <summary>
		/// <para>Contains information about a low-level keyboard input event.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-tagkbdllhookstruct typedef struct tagKBDLLHOOKSTRUCT {
		// DWORD vkCode; DWORD scanCode; DWORD flags; DWORD time; ULONG_PTR dwExtraInfo; } KBDLLHOOKSTRUCT, *LPKBDLLHOOKSTRUCT, *PKBDLLHOOKSTRUCT;
		[PInvokeData("winuser.h", MSDNShortId = "kbdllhookstruct.htm")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct KBDLLHOOKSTRUCT
		{
			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>A virtual-key code. The code must be a value in the range 1 to 254.</para>
			/// </summary>
			public uint vkCode;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>A hardware scan code for the key.</para>
			/// </summary>
			public uint scanCode;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>
			/// The extended-key flag, event-injected flags, context code, and transition-state flag. This member is specified as follows.
			/// An application can use the following values to test the keystroke flags. Testing LLKHF_INJECTED (bit 4) will tell you
			/// whether the event was injected. If it was, then testing LLKHF_LOWER_IL_INJECTED (bit 1) will tell you whether or not the
			/// event was injected from a process running at lower integrity level.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>LLKHF_EXTENDED (KF_EXTENDED &gt;&gt; 8)</term>
			/// <term>Test the extended-key flag.</term>
			/// </item>
			/// <item>
			/// <term>LLKHF_LOWER_IL_INJECTED 0x00000002</term>
			/// <term>Test the event-injected (from a process running at lower integrity level) flag.</term>
			/// </item>
			/// <item>
			/// <term>LLKHF_INJECTED 0x00000010</term>
			/// <term>Test the event-injected (from any process) flag.</term>
			/// </item>
			/// <item>
			/// <term>LLKHF_ALTDOWN (KF_ALTDOWN &gt;&gt; 8)</term>
			/// <term>Test the context code.</term>
			/// </item>
			/// <item>
			/// <term>LLKHF_UP (KF_UP &gt;&gt; 8)</term>
			/// <term>Test the transition-state flag.</term>
			/// </item>
			/// </list>
			/// <para>The following table describes the layout of this value.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Bits</term>
			/// <term>Description</term>
			/// </listheader>
			/// <item>
			/// <term>0</term>
			/// <term>
			/// Specifies whether the key is an extended key, such as a function key or a key on the numeric keypad. The value is 1 if the
			/// key is an extended key; otherwise, it is 0.
			/// </term>
			/// </item>
			/// <item>
			/// <term>1</term>
			/// <term>
			/// Specifies whether the event was injected from a process running at lower integrity level. The value is 1 if that is the
			/// case; otherwise, it is 0. Note that bit 4 is also set whenever bit 1 is set.
			/// </term>
			/// </item>
			/// <item>
			/// <term>2-3</term>
			/// <term>Reserved.</term>
			/// </item>
			/// <item>
			/// <term>4</term>
			/// <term>
			/// Specifies whether the event was injected. The value is 1 if that is the case; otherwise, it is 0. Note that bit 1 is not
			/// necessarily set when bit 4 is set.
			/// </term>
			/// </item>
			/// <item>
			/// <term>5</term>
			/// <term>The context code. The value is 1 if the ALT key is pressed; otherwise, it is 0.</term>
			/// </item>
			/// <item>
			/// <term>6</term>
			/// <term>Reserved.</term>
			/// </item>
			/// <item>
			/// <term>7</term>
			/// <term>The transition state. The value is 0 if the key is pressed and 1 if it is being released.</term>
			/// </item>
			/// </list>
			/// </summary>
			public uint flags;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>The time stamp for this message, equivalent to what GetMessageTime would return for this message.</para>
			/// </summary>
			public uint time;

			/// <summary>
			/// <para>Type: <c>ULONG_PTR</c></para>
			/// <para>Additional information associated with the message.</para>
			/// </summary>
			public UIntPtr dwExtraInfo;
		}

		/// <summary>
		/// <para>Contains information about a mouse event passed to a <c>WH_MOUSE</c> hook procedure, MouseProc.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-tagmousehookstruct typedef struct tagMOUSEHOOKSTRUCT {
		// POINT pt; HWND hwnd; UINT wHitTestCode; ULONG_PTR dwExtraInfo; } MOUSEHOOKSTRUCT, *LPMOUSEHOOKSTRUCT, *PMOUSEHOOKSTRUCT;
		[PInvokeData("winuser.h", MSDNShortId = "mousehookstruct.htm")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct MOUSEHOOKSTRUCT
		{
			/// <summary>
			/// <para>Type: <c>POINT</c></para>
			/// <para>The x- and y-coordinates of the cursor, in screen coordinates.</para>
			/// </summary>
			public System.Drawing.Point pt;

			/// <summary>
			/// <para>Type: <c>HWND</c></para>
			/// <para>A handle to the window that will receive the mouse message corresponding to the mouse event.</para>
			/// </summary>
			public HWND hwnd;

			/// <summary>
			/// <para>Type: <c>UINT</c></para>
			/// <para>The hit-test value. For a list of hit-test values, see the description of the WM_NCHITTEST message.</para>
			/// </summary>
			public uint wHitTestCode;

			/// <summary>
			/// <para>Type: <c>ULONG_PTR</c></para>
			/// <para>Additional information associated with the message.</para>
			/// </summary>
			public UIntPtr dwExtraInfo;
		}

		/// <summary>
		/// <para>Contains information about a mouse event passed to a <c>WH_MOUSE</c> hook procedure, MouseProc.</para>
		/// <para>
		/// This is an extension of the MOUSEHOOKSTRUCT structure that includes information about wheel movement or the use of the X button.
		/// </para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-tagmousehookstructex typedef struct tagMOUSEHOOKSTRUCTEX
		// { DWORD mouseData; base_class tagMOUSEHOOKSTRUCT; } MOUSEHOOKSTRUCTEX, *LPMOUSEHOOKSTRUCTEX, *PMOUSEHOOKSTRUCTEX;
		[PInvokeData("winuser.h", MSDNShortId = "mousehookstructex.htm")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct MOUSEHOOKSTRUCTEX
		{
			/// <summary>
			/// <para>Type: <c>POINT</c></para>
			/// <para>The x- and y-coordinates of the cursor, in screen coordinates.</para>
			/// </summary>
			public System.Drawing.Point pt;

			/// <summary>
			/// <para>Type: <c>HWND</c></para>
			/// <para>A handle to the window that will receive the mouse message corresponding to the mouse event.</para>
			/// </summary>
			public HWND hwnd;

			/// <summary>
			/// <para>Type: <c>UINT</c></para>
			/// <para>The hit-test value. For a list of hit-test values, see the description of the WM_NCHITTEST message.</para>
			/// </summary>
			public uint wHitTestCode;

			/// <summary>
			/// <para>Type: <c>ULONG_PTR</c></para>
			/// <para>Additional information associated with the message.</para>
			/// </summary>
			public UIntPtr dwExtraInfo;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>
			/// If the message is WM_MOUSEWHEEL, the HIWORD of this member is the wheel delta. The LOWORD is undefined and reserved. A
			/// positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel
			/// was rotated backward, toward the user. One wheel click is defined as WHEEL_DELTA, which is 120.
			/// </para>
			/// <para>
			/// If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, or WM_NCXBUTTONDBLCLK,
			/// the HIWORD of <c>mouseData</c> specifies which X button was pressed or released, and the LOWORD is undefined and reserved.
			/// This member can be one or more of the following values. Otherwise, <c>mouseData</c> is not used.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>XBUTTON1 0x0001</term>
			/// <term>The first X button was pressed or released.</term>
			/// </item>
			/// <item>
			/// <term>XBUTTON2 0x0002</term>
			/// <term>The second X button was pressed or released.</term>
			/// </item>
			/// </list>
			/// </summary>
			public uint mouseData;
		}

		/// <summary>
		/// <para>Contains information about a low-level mouse input event.</para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/desktop/api/winuser/ns-winuser-tagmsllhookstruct typedef struct tagMSLLHOOKSTRUCT {
		// POINT pt; DWORD mouseData; DWORD flags; DWORD time; ULONG_PTR dwExtraInfo; } MSLLHOOKSTRUCT, *LPMSLLHOOKSTRUCT, *PMSLLHOOKSTRUCT;
		[PInvokeData("winuser.h", MSDNShortId = "msllhookstruct.htm")]
		[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
		public struct MSLLHOOKSTRUCT
		{
			/// <summary>
			/// <para>Type: <c>POINT</c></para>
			/// <para>The x- and y-coordinates of the cursor, in per-monitor-aware screen coordinates.</para>
			/// </summary>
			public System.Drawing.Point pt;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>
			/// If the message is WM_MOUSEWHEEL, the high-order word of this member is the wheel delta. The low-order word is reserved. A
			/// positive value indicates that the wheel was rotated forward, away from the user; a negative value indicates that the wheel
			/// was rotated backward, toward the user. One wheel click is defined as <c>WHEEL_DELTA</c>, which is 120.
			/// </para>
			/// <para>
			/// If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, or WM_NCXBUTTONDBLCLK,
			/// the high-order word specifies which X button was pressed or released, and the low-order word is reserved. This value can be
			/// one or more of the following values. Otherwise, <c>mouseData</c> is not used.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>XBUTTON1 0x0001</term>
			/// <term>The first X button was pressed or released.</term>
			/// </item>
			/// <item>
			/// <term>XBUTTON2 0x0002</term>
			/// <term>The second X button was pressed or released.</term>
			/// </item>
			/// </list>
			/// </summary>
			public uint mouseData;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>
			/// The event-injected flags. An application can use the following values to test the flags. Testing LLMHF_INJECTED (bit 0) will
			/// tell you whether the event was injected. If it was, then testing LLMHF_LOWER_IL_INJECTED (bit 1) will tell you whether or
			/// not the event was injected from a process running at lower integrity level.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>LLMHF_INJECTED 0x00000001</term>
			/// <term>Test the event-injected (from any process) flag.</term>
			/// </item>
			/// <item>
			/// <term>LLMHF_LOWER_IL_INJECTED 0x00000002</term>
			/// <term>Test the event-injected (from a process running at lower integrity level) flag.</term>
			/// </item>
			/// </list>
			/// </summary>
			public uint flags;

			/// <summary>
			/// <para>Type: <c>DWORD</c></para>
			/// <para>The time stamp for this message.</para>
			/// </summary>
			public uint time;

			/// <summary>
			/// <para>Type: <c>ULONG_PTR</c></para>
			/// <para>Additional information associated with the message.</para>
			/// </summary>
			public UIntPtr dwExtraInfo;
		}

		/// <summary>
		/// <para>
		/// This topic describes the events that are generated by the operating system and by server applications. The constants are listed
		/// in alphabetical order.
		/// </para>
		/// <para>
		/// Prior to using these events, client applications should use Accessible Event Watcher to verify that these events are used by UI elements.
		/// </para>
		/// <para>
		/// For more information about events in general, see What Are WinEvents? and System Level and Object Level Events. For more
		/// information about the events sent by the system, see Appendix A: Supported User Interface Elements Reference.
		/// </para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/winauto/event-constants
		[PInvokeData("", MSDNShortId = "e27b135d-4faf-401e-a6c1-64ed0e1b5de5")]
		public static class EventConstants
		{
			/// <summary>
			/// The range of WinEvent constant values specified by the Accessibility Interoperability Alliance (AIA) for use across the
			/// industry. For more information, see Allocation of WinEvent IDs.
			/// </summary>
			public const uint EVENT_AIA_END = 0xAFFF;

			/// <summary>
			/// The range of WinEvent constant values specified by the Accessibility Interoperability Alliance (AIA) for use across the
			/// industry. For more information, see Allocation of WinEvent IDs.
			/// </summary>
			public const uint EVENT_AIA_START = 0xA000;

			/// <summary></summary>
			public const uint EVENT_CONSOLE_CARET = 0x4001;

			/// <summary></summary>
			public const uint EVENT_CONSOLE_END = 0x40FF;

			/// <summary></summary>
			public const uint EVENT_CONSOLE_END_APPLICATION = 0x4007;

			/// <summary></summary>
			public const uint EVENT_CONSOLE_LAYOUT = 0x4005;

			/// <summary></summary>
			public const uint EVENT_CONSOLE_START_APPLICATION = 0x4006;

			/// <summary></summary>
			public const uint EVENT_CONSOLE_UPDATE_REGION = 0x4002;

			/// <summary></summary>
			public const uint EVENT_CONSOLE_UPDATE_SCROLL = 0x4004;

			/// <summary></summary>
			public const uint EVENT_CONSOLE_UPDATE_SIMPLE = 0x4003;

			/// <summary>The highest possible event values.</summary>
			public const uint EVENT_MAX = 0x7FFFFFFF;

			/// <summary>The lowest possible event values.</summary>
			public const uint EVENT_MIN = 0x00000001;

			/// <summary>
			/// An object's KeyboardShortcut property has changed. Server applications send this event for their accessible objects.
			/// </summary>
			public const uint EVENT_OBJECT_ACCELERATORCHANGE = 0x8012;

			/// <summary>Sent when a window is cloaked. A cloaked window still exists, but is invisible to the user.</summary>
			public const uint EVENT_OBJECT_CLOAKED = 0x8017;

			/// <summary>
			/// A window object's scrolling has ended. Unlike EVENT_SYSTEM_SCROLLEND, this event is associated with the scrolling window.
			/// Whether the scrolling is horizontal or vertical scrolling, this event should be sent whenever the scroll action is completed.
			/// <para>
			/// The hwnd parameter of the WinEventProc callback function describes the scrolling window; the idObject parameter is
			/// OBJID_CLIENT, and the idChild parameter is CHILDID_SELF.
			/// </para>
			/// </summary>
			public const uint EVENT_OBJECT_CONTENTSCROLLED = 0x8015;

			/// <summary>
			/// An object has been created. The system sends this event for the following user interface elements: caret, header control,
			/// list-view control, tab control, toolbar control, tree view control, and window object. Server applications send this event
			/// for their accessible objects.
			/// <para>
			/// Before sending the event for the parent object, servers must send it for all of an object's child objects. Servers must
			/// ensure that all child objects are fully created and ready to accept IAccessible calls from clients before the parent object
			/// sends this event.
			/// </para>
			/// <para>
			/// Because a parent object is created after its child objects, clients must make sure that an object's parent has been created
			/// before calling IAccessible::get_accParent, particularly if in-context hook functions are used.
			/// </para>
			/// </summary>
			public const uint EVENT_OBJECT_CREATE = 0x8000;

			/// <summary>
			/// An object's DefaultAction property has changed. The system sends this event for dialog boxes. Server applications send this
			/// event for their accessible objects.
			/// </summary>
			public const uint EVENT_OBJECT_DEFACTIONCHANGE = 0x8011;

			/// <summary>An object's Description property has changed. Server applications send this event for their accessible objects.</summary>
			public const uint EVENT_OBJECT_DESCRIPTIONCHANGE = 0x800D;

			/// <summary>
			/// An object has been destroyed. The system sends this event for the following user interface elements: caret, header control,
			/// list-view control, tab control, toolbar control, tree view control, and window object. Server applications send this event
			/// for their accessible objects.
			/// <para>Clients assume that all of an object's children are destroyed when the parent object sends this event.</para>
			/// <para>
			/// After receiving this event, clients do not call an object's IAccessible properties or methods. However, the interface
			/// pointer must remain valid as long as there is a reference count on it (due to COM rules), but the UI element may no longer
			/// be present. Further calls on the interface pointer may return failure errors; to prevent this, servers create proxy objects
			/// and monitor their life spans.
			/// </para>
			/// </summary>
			public const uint EVENT_OBJECT_DESTROY = 0x8001;

			/// <summary>
			/// The user has ended a drag operation before dropping the dragged element on a drop target. The hwnd, idObject, and idChild
			/// parameters of the WinEventProc callback function identify the object being dragged.
			/// </summary>
			public const uint EVENT_OBJECT_DRAGCANCEL = 0x8022;

			/// <summary>
			/// The user dropped an element on a drop target. The hwnd, idObject, and idChild parameters of the WinEventProc callback
			/// function identify the object being dragged.
			/// </summary>
			public const uint EVENT_OBJECT_DRAGCOMPLETE = 0x8023;

			/// <summary>
			/// The user dropped an element on a drop target. The hwnd, idObject, and idChild parameters of the WinEventProc callback
			/// function identify the drop target.
			/// </summary>
			public const uint EVENT_OBJECT_DRAGDROPPED = 0x8026;

			/// <summary>
			/// The user dragged an element into a drop target's boundary. The hwnd, idObject, and idChild parameters of the WinEventProc
			/// callback function identify the drop target.
			/// </summary>
			public const uint EVENT_OBJECT_DRAGENTER = 0x8024;

			/// <summary>
			/// The user dragged an element out of a drop target's boundary. The hwnd, idObject, and idChild parameters of the WinEventProc
			/// callback function identify the drop target.
			/// </summary>
			public const uint EVENT_OBJECT_DRAGLEAVE = 0x8025;

			/// <summary>
			/// The user started to drag an element. The hwnd, idObject, and idChild parameters of the WinEventProc callback function
			/// identify the object being dragged.
			/// </summary>
			public const uint EVENT_OBJECT_DRAGSTART = 0x8021;

			/// <summary>The highest object event value.</summary>
			public const uint EVENT_OBJECT_END = 0x80FF;

			/// <summary>
			/// An object has received the keyboard focus. The system sends this event for the following user interface elements: list-view
			/// control, menu bar, pop-up menu, switch window, tab control, tree view control, and window object. Server applications send
			/// this event for their accessible objects.
			/// <para>The hwnd parameter of the WinEventProc callback function identifies the window that receives the keyboard focus.</para>
			/// </summary>
			public const uint EVENT_OBJECT_FOCUS = 0x8005;

			/// <summary>An object's Help property has changed. Server applications send this event for their accessible objects.</summary>
			public const uint EVENT_OBJECT_HELPCHANGE = 0x8010;

			/// <summary>
			/// An object is hidden. The system sends this event for the following user interface elements: caret and cursor. Server
			/// applications send this event for their accessible objects.
			/// <para>
			/// When this event is generated for a parent object, all child objects are already hidden. Server applications do not send this
			/// event for the child objects.
			/// </para>
			/// <para>
			/// Hidden objects include the STATE_SYSTEM_INVISIBLE flag; shown objects do not include this flag. The EVENT_OBJECT_HIDE event
			/// also indicates that the STATE_SYSTEM_INVISIBLE flag is set. Therefore, servers do not send the EVENT_STATE_CHANGE event in
			/// this case.
			/// </para>
			/// </summary>
			public const uint EVENT_OBJECT_HIDE = 0x8003;

			/// <summary>
			/// A window that hosts other accessible objects has changed the hosted objects. A client might need to query the host window to
			/// discover the new hosted objects, especially if the client has been monitoring events from the window. A hosted object is an
			/// object from an accessibility framework (MSAA or UI Automation) that is different from that of the host. Changes in hosted
			/// objects that are from the same framework as the host should be handed with the structural change events, such as
			/// EVENT_OBJECT_CREATE for MSAA. For more info see comments within winuser.h.
			/// </summary>
			public const uint EVENT_OBJECT_HOSTEDOBJECTSINVALIDATED = 0x8020;

			/// <summary>The size or position of an IME window has changed.</summary>
			public const uint EVENT_OBJECT_IME_CHANGE = 0x8029;

			/// <summary>An IME window has become hidden.</summary>
			public const uint EVENT_OBJECT_IME_HIDE = 0x8028;

			/// <summary>An IME window has become visible.</summary>
			public const uint EVENT_OBJECT_IME_SHOW = 0x8027;

			/// <summary>
			/// An object has been invoked; for example, the user has clicked a button. This event is supported by common controls and is
			/// used by UI Automation.
			/// <para>
			/// For this event, the hwnd, ID, and idChild parameters of the WinEventProc callback function identify the item that is invoked.
			/// </para>
			/// </summary>
			public const uint EVENT_OBJECT_INVOKED = 0x8013;

			/// <summary>
			/// An object that is part of a live region has changed. A live region is an area of an application that changes frequently
			/// and/or asynchronously.
			/// </summary>
			public const uint EVENT_OBJECT_LIVEREGIONCHANGED = 0x8019;

			/// <summary>
			/// An object has changed location, shape, or size. The system sends this event for the following user interface elements: caret
			/// and window objects. Server applications send this event for their accessible objects.
			/// <para>
			/// This event is generated in response to a change in the top-level object within the object hierarchy; it is not generated for
			/// any children that the object might have. For example, if the user resizes a window, the system sends this notification for
			/// the window, but not for the menu bar, title bar, scroll bar, or other objects that have also changed.
			/// </para>
			/// <para>
			/// The system does not send this event for every non-floating child window when the parent moves. However, if an application
			/// explicitly resizes child windows as a result of resizing the parent window, the system sends multiple events for the resized children.
			/// </para>
			/// <para>
			/// If an object's State property is set to STATE_SYSTEM_FLOATING, the server sends EVENT_OBJECT_LOCATIONCHANGE whenever the
			/// object changes location. If an object does not have this state, servers only trigger this event when the object moves in
			/// relation to its parent. For this event notification, the idChild parameter of the WinEventProc callback function identifies
			/// the child object that has changed.
			/// </para>
			/// </summary>
			public const uint EVENT_OBJECT_LOCATIONCHANGE = 0x800B;

			/// <summary>
			/// An object's Name property has changed. The system sends this event for the following user interface elements: check box,
			/// cursor, list-view control, push button, radio button, status bar control, tree view control, and window object. Server
			/// applications send this event for their accessible objects.
			/// </summary>
			public const uint EVENT_OBJECT_NAMECHANGE = 0x800C;

			/// <summary>An object has a new parent object. Server applications send this event for their accessible objects.</summary>
			public const uint EVENT_OBJECT_PARENTCHANGE = 0x800F;

			/// <summary>
			/// A container object has added, removed, or reordered its children. The system sends this event for the following user
			/// interface elements: header control, list-view control, toolbar control, and window object. Server applications send this
			/// event as appropriate for their accessible objects.
			/// <para>
			/// For example, this event is generated by a list-view object when the number of child elements or the order of the elements
			/// changes. This event is also sent by a parent window when the Z-order for the child windows changes.
			/// </para>
			/// </summary>
			public const uint EVENT_OBJECT_REORDER = 0x8004;

			/// <summary>
			/// The selection within a container object has changed. The system sends this event for the following user interface elements:
			/// list-view control, tab control, tree view control, and window object. Server applications send this event for their
			/// accessible objects.
			/// <para>
			/// This event signals a single selection: either a child is selected in a container that previously did not contain any
			/// selected children, or the selection has changed from one child to another.
			/// </para>
			/// <para>
			/// The hwnd and idObject parameters of the WinEventProc callback function describe the container; the idChild parameter
			/// identifies the object that is selected. If the selected child is a window that also contains objects, the idChild parameter
			/// is OBJID_WINDOW.
			/// </para>
			/// </summary>
			public const uint EVENT_OBJECT_SELECTION = 0x8006;

			/// <summary>
			/// A child within a container object has been added to an existing selection. The system sends this event for the following
			/// user interface elements: list box, list-view control, and tree view control. Server applications send this event for their
			/// accessible objects.
			/// <para>
			/// The hwnd and idObject parameters of the WinEventProc callback function describe the container. The idChild parameter is the
			/// child that is added to the selection.
			/// </para>
			/// </summary>
			public const uint EVENT_OBJECT_SELECTIONADD = 0x8007;

			/// <summary>
			/// An item within a container object has been removed from the selection. The system sends this event for the following user
			/// interface elements: list box, list-view control, and tree view control. Server applications send this event for their
			/// accessible objects.
			/// <para>This event signals that a child is removed from an existing selection.</para>
			/// <para>
			/// The hwnd and idObject parameters of the WinEventProc callback function describe the container; the idChild parameter
			/// identifies the child that has been removed from the selection.
			/// </para>
			/// </summary>
			public const uint EVENT_OBJECT_SELECTIONREMOVE = 0x8008;

			/// <summary>
			/// Numerous selection changes have occurred within a container object. The system sends this event for list boxes; server
			/// applications send it for their accessible objects.
			/// <para>
			/// This event is sent when the selected items within a control have changed substantially. The event informs the client that
			/// many selection changes have occurred, and it is sent instead of several EVENT_OBJECT_SELECTIONADD or
			/// EVENT_OBJECT_SELECTIONREMOVE events. The client queries for the selected items by calling the container object's
			/// IAccessible::get_accSelection method and enumerating the selected items.
			/// </para>
			/// <para>
			/// For this event notification, the hwnd and idObject parameters of the WinEventProc callback function describe the container
			/// in which the changes occurred.
			/// </para>
			/// </summary>
			public const uint EVENT_OBJECT_SELECTIONWITHIN = 0x8009;

			/// <summary>
			/// A hidden object is shown. The system sends this event for the following user interface elements: caret, cursor, and window
			/// object. Server applications send this event for their accessible objects.
			/// <para>
			/// Clients assume that when this event is sent by a parent object, all child objects are already displayed. Therefore, server
			/// applications do not send this event for the child objects.
			/// </para>
			/// <para>
			/// Hidden objects include the STATE_SYSTEM_INVISIBLE flag; shown objects do not include this flag. The EVENT_OBJECT_SHOW event
			/// also indicates that the STATE_SYSTEM_INVISIBLE flag is cleared. Therefore, servers do not send the EVENT_STATE_CHANGE event
			/// in this case.
			/// </para>
			/// </summary>
			public const uint EVENT_OBJECT_SHOW = 0x8002;

			/// <summary>
			/// An object's state has changed. The system sends this event for the following user interface elements: check box, combo box,
			/// header control, push button, radio button, scroll bar, toolbar control, tree view control, up-down control, and window
			/// object. Server applications send this event for their accessible objects.
			/// <para>For example, a state change occurs when a button object is clicked or released, or when an object is enabled or disabled.</para>
			/// <para>
			/// For this event notification, the idChild parameter of the WinEventProc callback function identifies the child object whose
			/// state has changed.
			/// </para>
			/// </summary>
			public const uint EVENT_OBJECT_STATECHANGE = 0x800A;

			/// <summary>
			/// The conversion target within an IME composition has changed. The conversion target is the subset of the IME composition
			/// which is actively selected as the target for user-initiated conversions.
			/// </summary>
			public const uint EVENT_OBJECT_TEXTEDIT_CONVERSIONTARGETCHANGED = 0x8030;

			/// <summary>
			/// An object's text selection has changed. This event is supported by common controls and is used by UI Automation.
			/// <para>
			/// The hwnd, ID, and idChild parameters of the WinEventProc callback function describe the item that is contained in the
			/// updated text selection.
			/// </para>
			/// </summary>
			public const uint EVENT_OBJECT_TEXTSELECTIONCHANGED = 0x8014;

			/// <summary>Sent when a window is uncloaked. A cloaked window still exists, but is invisible to the user.</summary>
			public const uint EVENT_OBJECT_UNCLOAKED = 0x8018;

			/// <summary>
			/// An object's Value property has changed. The system sends this event for the user interface elements that include the scroll
			/// bar and the following controls: edit, header, hot key, progress bar, slider, and up-down. Server applications send this
			/// event for their accessible objects.
			/// </summary>
			public const uint EVENT_OBJECT_VALUECHANGE = 0x800E;

			/// <summary>The range of event constant values reserved for OEMs. For more information, see Allocation of WinEvent IDs.</summary>
			public const uint EVENT_OEM_DEFINED_END = 0x01FF;

			/// <summary>The range of event constant values reserved for OEMs. For more information, see Allocation of WinEvent IDs.</summary>
			public const uint EVENT_OEM_DEFINED_START = 0x0101;

			/// <summary>An alert has been generated. Server applications should not send this event.</summary>
			public const uint EVENT_SYSTEM_ALERT = 0x0002;

			/// <summary>A preview rectangle is being displayed.</summary>
			public const uint EVENT_SYSTEM_ARRANGMENTPREVIEW = 0x8016;

			/// <summary>A window has lost mouse capture. This event is sent by the system, never by servers.</summary>
			public const uint EVENT_SYSTEM_CAPTUREEND = 0x0009;

			/// <summary>A window has received mouse capture. This event is sent by the system, never by servers.</summary>
			public const uint EVENT_SYSTEM_CAPTURESTART = 0x0008;

			/// <summary>A window has exited context-sensitive Help mode. This event is not sent consistently by the system.</summary>
			public const uint EVENT_SYSTEM_CONTEXTHELPEND = 0x000D;

			/// <summary>A window has entered context-sensitive Help mode. This event is not sent consistently by the system.</summary>
			public const uint EVENT_SYSTEM_CONTEXTHELPSTART = 0x000C;

			/// <summary>The active desktop has been switched.</summary>
			public const uint EVENT_SYSTEM_DESKTOPSWITCH = 0x0020;

			/// <summary>
			/// A dialog box has been closed. The system sends this event for standard dialog boxes; servers send it for custom dialog
			/// boxes. This event is not sent consistently by the system.
			/// </summary>
			public const uint EVENT_SYSTEM_DIALOGEND = 0x0011;

			/// <summary>
			/// A dialog box has been displayed. The system sends this event for standard dialog boxes, which are created using resource
			/// templates or Win32 dialog box functions. Servers send this event for custom dialog boxes, which are windows that function as
			/// dialog boxes but are not created in the standard way.
			/// <para>This event is not sent consistently by the system.</para>
			/// </summary>
			public const uint EVENT_SYSTEM_DIALOGSTART = 0x0010;

			/// <summary>
			/// An application is about to exit drag-and-drop mode. Applications that support drag-and-drop operations must send this event;
			/// the system does not send this event.
			/// </summary>
			public const uint EVENT_SYSTEM_DRAGDROPEND = 0x000F;

			/// <summary>
			/// An application is about to enter drag-and-drop mode. Applications that support drag-and-drop operations must send this event
			/// because the system does not send it.
			/// </summary>
			public const uint EVENT_SYSTEM_DRAGDROPSTART = 0x000E;

			/// <summary>The highest system event value.</summary>
			public const uint EVENT_SYSTEM_END = 0x00FF;

			/// <summary>
			/// The foreground window has changed. The system sends this event even if the foreground window has changed to another window
			/// in the same thread. Server applications never send this event.
			/// <para>
			/// For this event, the WinEventProc callback function's hwnd parameter is the handle to the window that is in the foreground,
			/// the idObject parameter is OBJID_WINDOW, and the idChild parameter is CHILDID_SELF.
			/// </para>
			/// </summary>
			public const uint EVENT_SYSTEM_FOREGROUND = 0x0003;

			/// <summary></summary>
			public const uint EVENT_SYSTEM_IME_KEY_NOTIFICATION = 0x0029;

			/// <summary>
			/// A menu from the menu bar has been closed. The system sends this event for standard menus; servers send it for custom menus.
			/// <para>
			/// For this event, the WinEventProc callback function's hwnd, idObject, and idChild parameters refer to the control that
			/// contains the menu bar or the control that activates the context menu. The hwnd parameter is the handle to the window that is
			/// related to the event. The idObject parameter is OBJID_MENU or OBJID_SYSMENU for a menu, or OBJID_WINDOW for a pop-up menu.
			/// The idChild parameter is CHILDID_SELF.
			/// </para>
			/// </summary>
			public const uint EVENT_SYSTEM_MENUEND = 0x0005;

			/// <summary>
			/// A pop-up menu has been closed. The system sends this event for standard menus; servers send it for custom menus.
			/// <para>When a pop-up menu is closed, the client receives this message, and then the EVENT_SYSTEM_MENUEND event.</para>
			/// <para>This event is not sent consistently by the system.</para>
			/// </summary>
			public const uint EVENT_SYSTEM_MENUPOPUPEND = 0x0007;

			/// <summary>
			/// A pop-up menu has been displayed. The system sends this event for standard menus, which are identified by HMENU, and are
			/// created using menu-template resources or Win32 menu functions. Servers send this event for custom menus, which are user
			/// interface elements that function as menus but are not created in the standard way. This event is not sent consistently by
			/// the system.
			/// </summary>
			public const uint EVENT_SYSTEM_MENUPOPUPSTART = 0x0006;

			/// <summary>
			/// A menu item on the menu bar has been selected. The system sends this event for standard menus, which are identified by
			/// HMENU, created using menu-template resources or Win32 menu API elements. Servers send this event for custom menus, which are
			/// user interface elements that function as menus but are not created in the standard way.
			/// <para>
			/// For this event, the WinEventProc callback function's hwnd, idObject, and idChild parameters refer to the control that
			/// contains the menu bar or the control that activates the context menu. The hwnd parameter is the handle to the window related
			/// to the event. The idObject parameter is OBJID_MENU or OBJID_SYSMENU for a menu, or OBJID_WINDOW for a pop-up menu. The
			/// idChild parameter is CHILDID_SELF.
			/// </para>
			/// <para>
			/// The system triggers more than one EVENT_SYSTEM_MENUSTART event that does not always correspond with the EVENT_SYSTEM_MENUEND event.
			/// </para>
			/// </summary>
			public const uint EVENT_SYSTEM_MENUSTART = 0x0004;

			/// <summary>A window object is about to be restored. This event is sent by the system, never by servers.</summary>
			public const uint EVENT_SYSTEM_MINIMIZEEND = 0x0017;

			/// <summary>A window object is about to be minimized. This event is sent by the system, never by servers.</summary>
			public const uint EVENT_SYSTEM_MINIMIZESTART = 0x0016;

			/// <summary>The movement or resizing of a window has finished. This event is sent by the system, never by servers.</summary>
			public const uint EVENT_SYSTEM_MOVESIZEEND = 0x000B;

			/// <summary>A window is being moved or resized. This event is sent by the system, never by servers.</summary>
			public const uint EVENT_SYSTEM_MOVESIZESTART = 0x000A;

			/// <summary>
			/// Scrolling has ended on a scroll bar. This event is sent by the system for standard scroll bar controls and for scroll bars
			/// that are attached to a window. Servers send this event for custom scroll bars, which are user interface elements that
			/// function as scroll bars but are not created in the standard way.
			/// <para>
			/// The idObject parameter that is sent to the WinEventProc callback function is OBJID_HSCROLL for horizontal scroll bars, and
			/// OBJID_VSCROLL for vertical scroll bars.
			/// </para>
			/// </summary>
			public const uint EVENT_SYSTEM_SCROLLINGEND = 0x0013;

			/// <summary>
			/// Scrolling has started on a scroll bar. The system sends this event for standard scroll bar controls and for scroll bars
			/// attached to a window. Servers send this event for custom scroll bars, which are user interface elements that function as
			/// scroll bars but are not created in the standard way.
			/// <para>
			/// The idObject parameter that is sent to the WinEventProc callback function is OBJID_HSCROLL for horizontal scrolls bars, and
			/// OBJID_VSCROLL for vertical scroll bars.
			/// </para>
			/// </summary>
			public const uint EVENT_SYSTEM_SCROLLINGSTART = 0x0012;

			/// <summary>
			/// A sound has been played. The system sends this event when a system sound, such as one for a menu, is played even if no sound
			/// is audible (for example, due to the lack of a sound file or a sound card). Servers send this event whenever a custom UI
			/// element generates a sound.
			/// <para>For this event, the WinEventProc callback function receives the OBJID_SOUND value as the idObject parameter.</para>
			/// </summary>
			public const uint EVENT_SYSTEM_SOUND = 0x0001;

			/// <summary>
			/// The user has released ALT+TAB. This event is sent by the system, never by servers. The hwnd parameter of the WinEventProc
			/// callback function identifies the window to which the user has switched.
			/// <para>
			/// If only one application is running when the user presses ALT+TAB, the system sends this event without a corresponding
			/// EVENT_SYSTEM_SWITCHSTART event.
			/// </para>
			/// </summary>
			public const uint EVENT_SYSTEM_SWITCHEND = 0x0015;

			/// <summary></summary>
			public const uint EVENT_SYSTEM_SWITCHER_APPDROPPED = 0x0026;

			/// <summary></summary>
			public const uint EVENT_SYSTEM_SWITCHER_APPGRABBED = 0x0024;

			/// <summary></summary>
			public const uint EVENT_SYSTEM_SWITCHER_APPOVERTARGET = 0x0025;

			/// <summary></summary>
			public const uint EVENT_SYSTEM_SWITCHER_CANCELLED = 0x0027;

			/// <summary>
			/// The user has pressed ALT+TAB, which activates the switch window. This event is sent by the system, never by servers. The
			/// hwnd parameter of the WinEventProc callback function identifies the window to which the user is switching.
			/// <para>
			/// If only one application is running when the user presses ALT+TAB, the system sends an EVENT_SYSTEM_SWITCHEND event without a
			/// corresponding EVENT_SYSTEM_SWITCHSTART event.
			/// </para>
			/// </summary>
			public const uint EVENT_SYSTEM_SWITCHSTART = 0x0014;

			/// <summary>
			/// The range of event constant values reserved for UI Automation event identifiers. For more information, see Allocation of
			/// WinEvent IDs.
			/// </summary>
			public const uint EVENT_UIA_EVENTID_END = 0x4EFF;

			/// <summary>
			/// The range of event constant values reserved for UI Automation event identifiers. For more information, see Allocation of
			/// WinEvent IDs.
			/// </summary>
			public const uint EVENT_UIA_EVENTID_START = 0x4E00;

			/// <summary>
			/// The range of event constant values reserved for UI Automation property-changed event identifiers. For more information, see
			/// Allocation of WinEvent IDs.
			/// </summary>
			public const uint EVENT_UIA_PROPID_END = 0x75FF;

			/// <summary>
			/// The range of event constant values reserved for UI Automation property-changed event identifiers. For more information, see
			/// Allocation of WinEvent IDs.
			/// </summary>
			public const uint EVENT_UIA_PROPID_START = 0x7500;
		}

		/// <summary>
		/// <para>
		/// This topic describes the Microsoft Active Accessibility object identifiers, 32-bit values that identify categories of accessible
		/// objects within a window. Microsoft Active Accessibility servers and Microsoft UI Automation providers use the object identifiers
		/// to determine the object to which a <c>WM_GETOBJECT</c> message request refers.
		/// </para>
		/// <para>
		/// Clients receive these values in their WinEventProc callback function and use them to identify parts of a window. Servers use
		/// these values to identify the corresponding parts of a window when calling <c>NotifyWinEvent</c> or when responding to the
		/// <c>WM_GETOBJECT</c> message.
		/// </para>
		/// <para>
		/// Servers can define custom object IDs to identify other categories of objects within their applications. Custom object IDs must
		/// be assigned positive values because Microsoft Active Accessibility reserves zero and all negative values for the following
		/// standard object identifiers.
		/// </para>
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/winauto/object-identifiers
		[PInvokeData("winuser.h", MSDNShortId = "dc1603f8-29e5-4acd-817a-c6957feaff6c")]
		public static class ObjectIdentifiers
		{
			/// <summary>The window itself rather than a child object.</summary>
			public const int OBJID_WINDOW = unchecked((int)0x00000000);

			/// <summary>The window's system menu.</summary>
			public const int OBJID_SYSMENU = unchecked((int)0xFFFFFFFF);

			/// <summary>The window's title bar.</summary>
			public const int OBJID_TITLEBAR = unchecked((int)0xFFFFFFFE);

			/// <summary>The window's menu bar.</summary>
			public const int OBJID_MENU = unchecked((int)0xFFFFFFFD);

			/// <summary>
			/// The window's client area. In most cases, the operating system controls the frame elements and the client object contains all
			/// elements that are controlled by the application. Servers only process the WM_GETOBJECT messages in which the lParam is
			/// OBJID_CLIENT, OBJID_WINDOW, or a custom object identifier.
			/// </summary>
			public const int OBJID_CLIENT = unchecked((int)0xFFFFFFFC);

			/// <summary>The window's vertical scroll bar.</summary>
			public const int OBJID_VSCROLL = unchecked((int)0xFFFFFFFB);

			/// <summary>The window's horizontal scroll bar.</summary>
			public const int OBJID_HSCROLL = unchecked((int)0xFFFFFFFA);

			/// <summary>The window's size grip: an optional frame component located at the lower-right corner of the window frame.</summary>
			public const int OBJID_SIZEGRIP = unchecked((int)0xFFFFFFF9);

			/// <summary>The text insertion bar (caret) in the window.</summary>
			public const int OBJID_CARET = unchecked((int)0xFFFFFFF8);

			/// <summary>The mouse pointer. There is only one mouse pointer in the system, and it is not a child of any window.</summary>
			public const int OBJID_CURSOR = unchecked((int)0xFFFFFFF7);

			/// <summary>
			/// An alert that is associated with a window or an application. System provided message boxes are the only UI elements that
			/// send events with this object identifier. Server applications cannot use the AccessibleObjectFromX functions with this object
			/// identifier. This is a known issue with Microsoft Active Accessibility.
			/// </summary>
			public const int OBJID_ALERT = unchecked((int)0xFFFFFFF6);

			/// <summary>
			/// A sound object. Sound objects do not have screen locations or children, but they do have name and state attributes. They are
			/// children of the application that is playing the sound.
			/// </summary>
			public const int OBJID_SOUND = unchecked((int)0xFFFFFFF5);

			/// <summary>
			/// An object identifier that Oleacc.dll uses internally. For more information, see Appendix F: Object Identifier Values for OBJID_QUERYCLASSNAMEIDX.
			/// </summary>
			public const int OBJID_QUERYCLASSNAMEIDX = unchecked((int)0xFFFFFFF4);

			/// <summary>
			/// In response to this object identifier, third-party applications can expose their own object model. Third-party applications
			/// can return any COM interface in response to this object identifier.
			/// </summary>
			public const int OBJID_NATIVEOM = unchecked((int)0xFFFFFFF0);
		}

		/// <summary>Provides a <see cref="SafeHandle"/> for <see cref="HHOOK"/> that is disposed using <see cref="UnhookWindowsHookEx"/>.</summary>
		public class SafeHHOOK : SafeHANDLE, IUserHandle
		{
			/// <summary>Initializes a new instance of the <see cref="SafeHHOOK"/> class and assigns an existing handle.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			/// <param name="ownsHandle">
			/// <see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).
			/// </param>
			public SafeHHOOK(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

			/// <summary>Initializes a new instance of the <see cref="SafeHHOOK"/> class.</summary>
			private SafeHHOOK() : base() { }

			/// <summary>Performs an implicit conversion from <see cref="SafeHHOOK"/> to <see cref="HHOOK"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator HHOOK(SafeHHOOK h) => h.handle;

			/// <inheritdoc/>
			protected override bool InternalReleaseHandle() => UnhookWindowsHookEx(this);
		}
	}
}